/**
 * 
 */
package com.module.hq.ui.mono.heroviewer.widgets;

import com.dalonedrau.jogl.engine.Action;
import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.InputEvent;
import com.dalonedrau.jogl.engine.Interface;
import com.dalonedrau.jogl.engine.JOGLErrorHandler;
import com.dalonedrau.jogl.opengl.sprite.BasicSpriteObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteBase;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.jogl.opengl.ui.Button;
import com.dalonedrau.jogl.opengl.ui.Label;
import com.dalonedrau.jogl.opengl.ui.UIFactory;
import com.dalonedrau.jogl.opengl.ui.border.AbstractHighlightBorder;
import com.dalonedrau.jogl.opengl.ui.panel.LandscapePagePanel;
import com.dalonedrau.jogl.opengl.ui.panel.Panel;
import com.dalonedrau.jogl.opengl.ui.panel.PortraitPagePanel;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.module.hq.bus.globals.SpellConsts;
import com.module.hq.ui.mono.borders.HQMonoTooltipBorder;

/**
 * Dialog window to choose which spell groups the character knows.
 * @author Donald
 */
public final class SpellFamilyChooserDialog extends PortraitPagePanel {
	/** the elemental school of air magic. */
	public static final int					ELEM_AIR	= 0;
	/** the elemental school of earth magic. */
	public static final int					ELEM_EARTH	= 1;
	/** the elemental school of fire magic. */
	public static final int					ELEM_FIRE	= 2;
	/** the elemental school of water magic. */
	public static final int					ELEM_WATER	= 3;
	/**
	 * the one and only instance of the <code>SpellFamilyChooserDialog</code>
	 * class.
	 */
	private static SpellFamilyChooserDialog	instance;
	/**
	 * Render Gives access to the singleton instance of
	 * {@link SpellFamilyChooserDialog}.
	 * @return {@link SpellFamilyChooserDialog}
	 */
	public static SpellFamilyChooserDialog getInstance() {
		if (SpellFamilyChooserDialog.instance == null) {
			SpellFamilyChooserDialog.instance = new SpellFamilyChooserDialog();
		}
		return SpellFamilyChooserDialog.instance;
	}
	/** the okay button. */
	private Button		btnOkay;
	/** the list of magic buttons. */
	private Button[]	buttons			= new Button[GlobalConsts.INT_004];
	/** the elements selected. */
	private long		elements;
	/** the list of elements selected, in order of selection. */
	private int[]		firstSelected	= new int[GlobalConsts.INT_003];
	/** the dialog's main label. */
	private Label		lbl;
	/** the number of spells allowed. */
	private int			numAllowed;
	/** the list of selected images. */
	private String[]	selImages		= new String[] {
										"hq_ultima_spell_elem_btn_air_sel",
										"hq_ultima_spell_elem_btn_earth_sel",
										"hq_ultima_spell_elem_btn_fire_sel",
										"hq_ultima_spell_elem_btn_water_sel"
										};
	/** the list of unselected images. */
	private String[]	unselImages		= new String[] {
										"hq_ultima_spell_elem_btn_air_unsel",
										"hq_ultima_spell_elem_btn_earth_unsel",
										"hq_ultima_spell_elem_btn_fire_unsel",
										"hq_ultima_spell_elem_btn_water_unsel"
										};
	/** Creates a new instance of {@link SpellFamilyChooserDialog}. */
	private SpellFamilyChooserDialog() {
		super(Panel.PORTRAIT_CENTER);
		super.setBorder(new HQMonoTooltipBorder());
		final SpellFamilyChooserDialog me = this;
		try {
			lbl = UIFactory.getInstance().getStandardH1Label(
					"This character is a spellcaster.  Please choose 1 "
							+ "school of elemental magic to learn.");
			int w = "Please choose 1 schools of".length();
			w *= UIFactory.getInstance().getH1FontCharacterMetrics().width;
			lbl.setMaximumWidth(231);
			super.addChild(lbl);
			super.addChild(UIFactory.getInstance().getSpacer(
					1, GlobalConsts.INT_003));
			btnOkay = UIFactory.getInstance().getStandardH1Button("Okay");
			btnOkay.setHighlightBorder(
					new AbstractHighlightBorder(btnOkay.getId(),
							"widget_highlight"));
			btnOkay.addAction(new Action() {
				/**
				 * {@inheritDoc}
				 */
				@Override
				public void performAction() {
					try {
						InputEvent.getInstance().addAction(
								me, // object
								me.getClass().getMethod(
										"clickOkay", null),
								null
								);
					} catch (Exception ex) {
						JOGLErrorHandler.getInstance().fatalError(ex);
					}
				}
			});
			btnOkay.setActive(false);
			super.addChild(createButtonPanel());
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		super.addChild(UIFactory.getInstance().getSpacer(
				1, GlobalConsts.INT_003));
		super.addChild(btnOkay);
	}
	/**
	 * Adds a school of elemental magic selected.
	 * @param elem the element
	 * @throws Exception if an error occurs
	 */
	private void addElement(final int elem) throws Exception {
		// count num elements selected
		int numSelected = 0;
		for (int i = 0; i < GlobalConsts.INT_004; i++) {
			if (elementSelected(i)) {
				numSelected++;
			}
		}
		if (numSelected + 1 > numAllowed) {
			// adjust the array
			int old = firstSelected[0];
			for (int i = 0; i < firstSelected.length - 1; i++) {
				firstSelected[i] = firstSelected[i + 1];
			}
			removeElement(old);
			buttons[old].getSprite().setImageRefId(
					SpriteImageObjectFactory.getInstance().getImageRefId(
							unselImages[old]));
			// enable the okay button
			btnOkay.setActive(true);
		} else if (numSelected + 1 == numAllowed) {
			btnOkay.setActive(true);
		} else {
			btnOkay.setActive(false);
		}
		if (numSelected >= numAllowed) {
			firstSelected[numAllowed - 1] = elem;
		} else {
			firstSelected[numSelected] = elem;
		}
		elements |= 1 << elem;
	}
	/**
	 * Changes a spell button.
	 * @param element the element selected
	 * @throws Exception if an error occurs
	 */
	public void changeSpellButton(final int element) throws Exception {
		int refId = 0;
		if (elementSelected(element)) {
			removeElement(element);
			// change the image
			refId = SpriteImageObjectFactory.getInstance().getImageRefId(
					unselImages[element]);
		} else {
			addElement(element);
			refId = SpriteImageObjectFactory.getInstance().getImageRefId(
					selImages[element]);
		}
		buttons[element].getSprite().setImageRefId(refId);
	}
	/**
	 * Handles the okay button being clicked.
	 * @throws Exception if an error occurs
	 */
	public void clickOkay() throws Exception {
		for (int i = 0; i < GlobalConsts.INT_004; i++) {
			if (elementSelected(i)) {
				int i1 = i + GlobalConsts.INT_004;
				int i2 = i + GlobalConsts.INT_008;
				HQHeroViewer.getInstance().addSpellToHerosKnowledge(
								SpellConsts.SPELL_BIT_FLAGS[i]);
				HQHeroViewer.getInstance().addSpellToHerosKnowledge(
								SpellConsts.SPELL_BIT_FLAGS[i1]);
				HQHeroViewer.getInstance().addSpellToHerosKnowledge(
								SpellConsts.SPELL_BIT_FLAGS[i2]);
			}
		}
		// clear all buttons;
		for (int i = 0; i < GlobalConsts.INT_004; i++) {
			buttons[i].getSprite().setImageRefId(
						SpriteImageObjectFactory.getInstance().getImageRefId(
								unselImages[i]));
		}
		btnOkay.setActive(false);
		// remove all selections
		elements = 0;
		// hide
		SpellFamilyChooserDialog.instance.setVisible(false);
		Interface.getInstance().hideDialog(SpellFamilyChooserDialog.instance);
	}
	/**
	 * Creates the magic buttons panel.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel createButtonPanel() throws Exception {
		final SpellFamilyChooserDialog me = this;
		Panel container = new PortraitPagePanel(Panel.PORTRAIT_CENTER);
		Panel top = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		Panel bottom = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject img =
				SpriteImageObjectFactory.getInstance().getImageByName(
						unselImages[0]);
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		buttons[0] = new Button(sb);
		buttons[0].addAction(new Action() {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public void performAction() {
				try {
					InputEvent.getInstance().addAction(
							me, // object
							me.getClass().getMethod(
									"changeSpellButton", 
									new Class[] { int.class }
							),
							new Integer[] { 
								SpellFamilyChooserDialog.ELEM_AIR }
							);
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
			}
		});
		top.addChild(buttons[0]);
		top.addChild(UIFactory.getInstance().getSpacer(
				GlobalConsts.INT_004, 1));

		sb = new BasicSpriteObject();
		img = SpriteImageObjectFactory.getInstance().getImageByName(
				unselImages[1]);
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		buttons[1] = new Button(sb);
		buttons[1].addAction(new Action() {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public void performAction() {
				try {
					InputEvent.getInstance().addAction(
							me, // object
							me.getClass().getMethod(
									"changeSpellButton", 
									new Class[] { int.class }
							),
							new Integer[] { 
								SpellFamilyChooserDialog.ELEM_EARTH }
							);
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
			}
		});
		top.addChild(buttons[1]);

		sb = new BasicSpriteObject();
		img = SpriteImageObjectFactory.getInstance().getImageByName(
				unselImages[2]);
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		buttons[2] = new Button(sb);
		buttons[2].addAction(new Action() {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public void performAction() {
				try {
					InputEvent.getInstance().addAction(
							me, // object
							me.getClass().getMethod(
									"changeSpellButton", 
									new Class[] { int.class }
							),
							new Integer[] { 
								SpellFamilyChooserDialog.ELEM_FIRE }
							);
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
			}
		});
		bottom.addChild(buttons[2]);
		bottom.addChild(UIFactory.getInstance().getSpacer(
				GlobalConsts.INT_004, 1));

		sb = new BasicSpriteObject();
		img = SpriteImageObjectFactory.getInstance().getImageByName(
				unselImages[GlobalConsts.INT_003]);
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		buttons[GlobalConsts.INT_003] = new Button(sb);
		buttons[GlobalConsts.INT_003].addAction(new Action() {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public void performAction() {
				try {
					InputEvent.getInstance().addAction(
							me, // object
							me.getClass().getMethod(
									"changeSpellButton", 
									new Class[] { int.class }
							),
							new Integer[] { 
								SpellFamilyChooserDialog.ELEM_WATER }
							);
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
			}
		});
		bottom.addChild(buttons[GlobalConsts.INT_003]);
		container.addChild(top);
		container.addChild(UIFactory.getInstance().getSpacer(
				GlobalConsts.INT_004, GlobalConsts.INT_004));
		container.addChild(bottom);
		return container;
	}
	/**
	 * Determines if the user selected a specific element.
	 * @param elem the element
	 * @return true if the user selected a specific element; false otherwise
	 */
	private boolean elementSelected(final long elem) {
		return (elements & 1 << elem) == 1 << elem;
	}
	/**
	 * Removes an element.
	 * @param elem the element
	 */
	private void removeElement(final long elem) {
		elements &= ~(1 << elem);
		btnOkay.setActive(false);
	}
	/**
	 * Sets the number of elemental schools of magic the character is allowed to
	 * learn.
	 * @param val the numAllowed to set
	 */
	public void setNumAllowed(final int val) {
		numAllowed = val;
		if (val == 1) {
			lbl.setText("This hero is a spellcaster.  Please choose 1 school "
					+ "of elemental magic to learn:");
		} else {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("This hero is a spellcaster.  Please choose ");
			sb.append(numAllowed);
			sb.append(" schools of elemental magic to learn:");
			lbl.setText(sb.toString());
			sb.returnToPool();
		}
	}
}
